"""交互式修改相关节点"""

import yaml
from pocketflow import AsyncNode
from ..utils.call_llm import call_llm_async
from ..utils.json_modifier import json_modifier

class InteractiveChatNode(AsyncNode):
    """交互式对话修改节点，支持用户与AI对话来修改JSON内容"""
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.categories = [
            "身份与访问控制",
            "数据安全", 
            "系统与网络安全",
            "日志与应急管理",
            "物理与环境安全",
            "合作与合规管理"
        ]
    
    async def prep_async(self, shared):
        """准备交互式对话上下文"""
        current_json = shared["final_output"]
        modification_log = shared.get("modification_log", [])
        output_path = shared.get("output_path", "output.json")
        
        return {
            "current_json": current_json,
            "modification_log": modification_log,
            "categories": self.categories,
            "output_path": output_path
        }
    
    async def exec_async(self, context):
        """执行交互式对话循环"""
        print("\n" + "="*60)
        print("🤖 进入交互式修改模式")
        print("您可以通过自然语言告诉我如何修改JSON内容")
        print("可用命令: 'help' - 帮助, 'history' - 查看修改记录, 'rollback' - 回滚, 'done' - 完成")
        print("="*60)
        
        current_json = context["current_json"]
        modification_log = context["modification_log"]
        
        while True:
            try:
                # 获取用户输入
                user_input = input("\n💬 请输入您的修改需求: ").strip()
                
                if not user_input:
                    continue
                
                # 处理特殊命令
                if user_input.lower() == 'done':
                    print("✅ 交互式修改完成")
                    break
                elif user_input.lower() == 'help':
                    self._show_help()
                    continue
                elif user_input.lower() == 'history':
                    print(json_modifier.get_history_summary(modification_log))
                    continue
                elif user_input.lower() == 'rollback':
                    rolled_back_data = json_modifier.rollback_last_modification(modification_log)
                    if rolled_back_data:
                        current_json = rolled_back_data
                        print("↩️  已回滚到上一个版本")
                    else:
                        print("❌ 没有可回滚的修改记录")
                    continue
                
                # 使用LLM分析用户意图（返回列表）
                modifications = await self._analyze_user_intent(user_input, current_json)
                
                if not modifications:
                    print("❌ 无法理解您的修改需求，请重新描述")
                    continue
                
                # 显示修改建议并确认
                if not self._confirm_modification(modifications if isinstance(modifications, list) else modifications):
                    continue
                
                # 执行修改（尽力而为）：交互前一次性快照，逐步执行但不逐步写历史
                try:
                    # 交互前快照
                    backup = json_modifier.begin_snapshot(current_json)
                    ops = modifications if isinstance(modifications, list) else [modifications]
                    failures = []
                    for idx, op in enumerate(ops, 1):
                        try:
                            current_json = json_modifier.apply_modification(
                                current_json, op, modification_log, add_history=False
                            )
                            at = f"{op.get('action')} {op.get('target','')}".strip()
                            print(f"✅ 第{idx}步成功: {at}")
                        except Exception as e:
                            print(f"❌ 第{idx}步失败: {str(e)}")
                            failures.append(f"step {idx}: {str(e)}")
                    # 本次交互一次性写入历史
                    desc = f"batch ops: {len(ops)}; failures: {len(failures)}"
                    json_modifier.commit_snapshot(modification_log, backup, action='batch', target='multi', description=desc)
                    print("✅ 本次交互已完成")
                    self._show_current_stats(current_json)
                    
                except Exception as e:
                    print(f"❌ 修改失败: {str(e)}")
                    
            except KeyboardInterrupt:
                print("\n\n👋 用户取消操作")
                break
            except Exception as e:
                print(f"❌ 发生错误: {str(e)}")
        
        return {
            "modified_json": current_json,
            "modification_log": modification_log
        }
    
    async def post_async(self, shared, prep_res, exec_res):
        """保存修改结果"""
        if exec_res:
            # 更新共享存储
            # 统一为字典对象存储
            shared["final_output"] = exec_res["modified_json"]
            shared["modification_log"] = exec_res["modification_log"]
        
        return "finalize"
    
    async def _analyze_user_intent(self, user_input: str, current_json: dict):
        """使用LLM分析用户修改意图，默认返回列表[List[dict]]"""
        # 获取现有模块列表
        existing_modules = list(set(item.get('module', '') for item in current_json.get('items', [])))
        
        # 获取示例项目结构
        sample_item = current_json.get('items', [{}])[0] if current_json.get('items') else {}
        
        prompt = f"""
你是一个JSON修改助手。用户想要修改安全评估证明材料清单JSON。

当前JSON结构概览:
- 总项目数: {len(current_json.get('items', []))}
- 包含的模块: {existing_modules}

用户请求: {user_input}

请分析用户意图并返回修改指令。支持的操作:

1. delete - 删除项目
   支持格式: "id:项目ID", "index:索引号", "module:模块名"
   
2. add - 添加项目 
   必须包含完整的项目对象，包含以下必需字段:
   - id: 唯一标识符 (生成UUID格式)
   - module: 模块名称 (从现有模块选择或创建新模块)
   - category: 分类名称 (通常与模块名相同)
   - checkpoint: 评估细项描述 (具体的检查点说明)
   - materials: 证明材料列表 (数组，包含3-5个相关材料)
   - notes: 补充说明 (可选)
   
3. update - 更新项目
   支持格式: "id:项目ID", "index:索引号"

项目结构示例:
{sample_item}

返回格式（务必仅输出一个 YAML 代码块，且为列表形式）:
```yaml
- action: delete/add/update
  target: 目标标识 (删除和更新时需要)
  value: 新值或更新内容 (添加和更新时需要，添加时必须包含所有必需字段)
  description: 操作描述
```

注意: 
- 添加操作时，value必须是完整的项目对象，包含所有必需字段
- 删除模块时使用 "module:模块名" 格式
- 生成的ID应该是UUID格式的唯一标识符
- 如果只有一个操作，也请返回长度为1的列表

如果无法理解用户意图，请返回一个空列表 []。
"""
        
        try:
            response = await call_llm_async(prompt)
            
            # 提取并聚合所有yaml列表/对象
            ops = []
            if "```yaml" in response:
                parts = response.split("```yaml")
                for seg in parts[1:]:
                    block = seg.split("```")[0].strip()
                    if not block:
                        continue
                    try:
                        data = yaml.safe_load(block)
                        if isinstance(data, list):
                            ops.extend([d for d in data if isinstance(d, dict)])
                        elif isinstance(data, dict):
                            ops.append(data)
                    except Exception:
                        continue
                if ops:
                    return ops
            # 兜底：尝试整体解析
            try:
                data = yaml.safe_load(response)
                if isinstance(data, list):
                    return [d for d in data if isinstance(d, dict)]
                if isinstance(data, dict):
                    return [data]
            except Exception:
                pass
            
        except Exception as e:
            print(f"分析用户意图时出错: {e}")
        
        return None
    
    def _confirm_modification(self, modification) -> bool:
        """确认修改操作，支持单个dict或列表list[dict]"""
        if isinstance(modification, list):
            print(f"\n📝 本次将执行 {len(modification)} 个操作:")
            for i, m in enumerate(modification, 1):
                action = m.get('action')
                target = m.get('target', '')
                desc = m.get('description', '')
                print(f"   {i}. {action} - {target} | {desc}")
        else:
            action = modification.get('action')
            description = modification.get('description', '未知操作')
            print(f"\n📝 修改建议: {description}")
            print(f"   操作类型: {action}")
            if action == 'add':
                value = modification.get('value', {})
                print(f"   将添加: {value.get('module', '')}/{value.get('checkpoint', '')}")
            elif action in ['delete', 'update']:
                target = modification.get('target', '')
                print(f"   目标: {target}")
        confirm = input("确认执行此修改吗？(y/n): ").strip().lower()
        return confirm in ['y', 'yes', '是']
    
    def _show_help(self):
        """显示帮助信息"""
        help_text = """
📖 交互式修改帮助:

🔧 修改操作:
  - "删除第3个项目" 或 "删除ID为xxx的项目"
  - "为数据安全模块添加数据备份评估项"
  - "修改第1个项目的材料清单"

📋 特殊命令:
  - 'help' - 显示此帮助
  - 'history' - 查看修改记录
  - 'rollback' - 回滚上次修改
  - 'done' - 完成修改

💡 提示: 请用自然语言描述您的修改需求，AI会理解并执行相应操作。
        """
        print(help_text)
    
    def _show_current_stats(self, current_json: dict):
        """显示当前JSON统计信息"""
        items = current_json.get('items', [])
        modules = {}
        for item in items:
            module = item.get('module', '未知')
            modules[module] = modules.get(module, 0) + 1
        
        print(f"📊 当前状态: 共 {len(items)} 个项目")
        for module, count in modules.items():
            print(f"   - {module}: {count} 项")


class ApplyUserInputNode(AsyncNode):
    """无控制台交互的用户输入节点：基于 shared['user_input'] 修改 JSON。

    复用：
    - `InteractiveChatNode._analyze_user_intent` 进行LLM意图解析
    - `json_modifier.apply_modification` 执行安全修改并记录历史
    """

    async def prep_async(self, shared):
        current_json = shared.get("final_output", {})

        return {
            "current_json": current_json,
            "modification_log": shared.get("modification_log", []),
            "user_input": shared.get("user_input", "").strip(),
        }

    async def exec_async(self, context):
        current_json = context["current_json"]
        modification_log = context["modification_log"]
        user_input = context["user_input"]

        if not user_input:
            return {"ok": False, "message": "empty user_input", "modified_json": current_json, "modification_log": modification_log}

        helper = InteractiveChatNode()
        modifications = await helper._analyze_user_intent(user_input, current_json)

        if not modifications:
            return {"ok": False, "message": "unable to analyze user intent", "modified_json": current_json, "modification_log": modification_log}

        ops = modifications if isinstance(modifications, list) else [modifications]
        failures = []
        # 交互前一次性快照
        backup = json_modifier.begin_snapshot(current_json)
        for idx, op in enumerate(ops, 1):
            try:
                print(f"{idx} 步操作类型：{op.get('action', '')} 操作内容：{op.get('description', '')}")
                current_json = json_modifier.apply_modification(current_json, op, modification_log, add_history=False)
            except Exception as e:
                print(f"{idx} 步操作失败：{str(e)}")
                failures.append(f"step {idx}: {str(e)}")
        # 一次性交互历史
        desc = f"batch ops: {len(ops)}; failures: {len(failures)}"
        json_modifier.commit_snapshot(modification_log, backup, action='batch', target='multi', description=desc)
        message = "; ".join(failures) if failures else ""
        return {"ok": len(failures) == 0, "message": message, "modified_json": current_json, "modification_log": modification_log}

    async def post_async(self, shared, prep_res, exec_res):
        error_log = shared.setdefault("error_log", [])

        if not exec_res:
            error_log.append("no exec result")
            return "default"

        if exec_res.get("ok"):
            shared["final_output"] = exec_res.get("modified_json", {})
            shared["modification_log"] = exec_res.get("modification_log", shared.get("modification_log", []))
        else:
            # 记录 message 作为错误信息（尽力而为场景下包含失败步骤）
            msg = exec_res.get("message") or exec_res.get("error")
            if msg:
                error_log.append(msg)

        return "default"
